﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="NotFoundOperationsProviderException.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Exceptions
{
    #region Usings

    using System;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Security;

    using ExulLibrary.Mathematics.LinearAlgebra.Properties;

    #endregion

    /// <summary>
    ///     Describes an error for case when operations provider required for some operations is not found.
    /// </summary>
    [Serializable]
    public sealed class NotFoundOperationsProviderException : InvalidOperationException
    {
        #region Constructors and Destructors

        #region public

        /// <summary>
        ///     Initializes a new instance of the <see cref="NotFoundOperationsProviderException"/> class.
        /// </summary>
        /// <param name="providerType">
        ///     The type of required provider.
        /// </param>
        /// <param name="containerType">
        ///     The type of container that should contain the provider.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="providerType"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="containerType"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        public NotFoundOperationsProviderException(Type providerType, Type containerType)
            : this(providerType, containerType, null)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="NotFoundOperationsProviderException"/> class.
        /// </summary>
        /// <param name="providerType">
        ///     The type of required provider.
        /// </param>
        /// <param name="containerType">
        ///     The type of container that should contain the provider.
        /// </param>
        /// <param name="innerException">
        ///     The inner exception.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="providerType"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="containerType"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        public NotFoundOperationsProviderException(Type providerType, Type containerType, Exception innerException)
            : base(Resources.ProviderIsNotFound, innerException)
        {
            if (providerType == null)
            {
                throw new ArgumentNullException("providerType");
            }

            if (containerType == null)
            {
                throw new ArgumentNullException("containerType");
            }

            this.ProviderType = providerType;
            this.ContainerType = containerType;
        }

        #endregion

        #region private

        /// <summary>
        ///     Initializes a new instance of the <see cref="NotFoundOperationsProviderException"/> class.
        /// </summary>
        /// <param name="info">
        ///     The object that holds the serialized object data.
        /// </param>
        /// <param name="context">
        ///     The contextual information about the source or destination.
        /// </param>
        private NotFoundOperationsProviderException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            this.ProviderType = (Type)info.GetValue("ProviderType", typeof(Type));
            this.ContainerType = (Type)info.GetValue("ContainerType", typeof(Type));
        }

        #endregion

        #endregion

        #region Properties

        #region public

        /// <summary>
        ///     Gets the type of container that should contain the provider.
        /// </summary>
        /// <value>
        ///     The type of container that should contain the provider.
        /// </value>
        public Type ContainerType
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the type of required provider.
        /// </summary>
        /// <value>
        ///     The type of required provider.
        /// </value>
        public Type ProviderType
        {
            get;
            private set;
        }

        #endregion

        #endregion

        #region Overridden Properties

        #region public

        /// <summary>
        ///     Gets a message that describes the current exception.
        /// </summary>
        /// <value>
        ///     The error message that explains the reason for the exception, or an empty string.
        /// </value>
        public override string Message
        {
            get
            {
                return string.Format(
                    CultureInfo.CurrentCulture, base.Message, this.ContainerType.FullName, this.ProviderType.FullName);
            }
        }

        #endregion

        #endregion

        #region Overridden Methods

        #region public

        /// <summary>
        ///     When overridden in a derived class, sets the <see cref="SerializationInfo"/> with information about the exception.
        /// </summary>
        /// <param name="info">
        ///     The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.
        /// </param>
        /// <param name="context">
        ///     The <see cref="StreamingContext"/> that contains contextual information about the source or destination.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="info"/> is <see langword="null"/>.
        /// </exception>
        [SecurityCritical]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);

            info.AddValue("ProviderType", this.ProviderType);
            info.AddValue("ContainerType", this.ContainerType);
        }

        #endregion

        #endregion
    }
}